package com.s7.ui.exception;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Looper;
import android.widget.Toast;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 全局异常处理工具
 */
public class CrashHandler implements UncaughtExceptionHandler {

    public static final String TAG = "CrashHandler";

    //系统默认的UncaughtException处理类
    private UncaughtExceptionHandler mDefaultHandler;
    //CrashHandler 实例
    private static volatile CrashHandler instance;
    //程序的Context对象
    private Context mContext;

    // 回调接口
    private OnCrashHandlerListener mListener;

    /**
     * 无参构造
     */
    public CrashHandler() {
    }

    /**
     * 获取CrashHandler实例 ,单例模式
     */
    public static CrashHandler getInstance() {
        if (instance == null)
            synchronized (CrashHandler.class) {
                if (instance == null) {
                    instance = new CrashHandler();
                }
            }
        return instance;
    }

    /**
     * 初始化
     */
    public CrashHandler init(Context context) {
        mContext = context;
        //获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
        return this;
    }

    /**
     * 初始化
     */
    public CrashHandler init(Context context, OnCrashHandlerListener mListener) {
        mContext = context;
        this.mListener = mListener;
        //获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
        return this;
    }

    /**
     * 程序崩溃会被该方法捕获到   在此添加逻辑是自己处理还是交给系统异常处理
     * handleException是自己处理异常的方法
     */
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        if (!handleException(throwable) && mDefaultHandler != null) {
            //如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, throwable);
        } else {

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (mListener != null) {
                mListener.onException();
            }
        }
    }

    /**
     * 添加自己处理异常的方法
     * 在这里收集收集的设备信息
     * 保存异常文件
     * @param ex
     * @return
     */
    protected boolean handleException(Throwable ex) {

        if (ex == null || mContext == null)
            return false;

        try {
            // 收集设备参数信息
            savcExceptionToData(ex);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 弹出提示信息
        new Thread(new Runnable() {
            public void run() {
                Looper.prepare();
                Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出。", Toast.LENGTH_SHORT).show();
                Looper.loop();
            }
        }).start();
        return true;

    }

    /**
     * 出现异常写到异常对象中，用以上传到服务器
     * @param ex
     * @throws Exception
     */
    private void savcExceptionToData(final Throwable ex) throws Exception {

        /**
         * 获取当前时间
         */
        SimpleDateFormat formatdate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        final String time = formatdate.format(new Date(System.currentTimeMillis()));

        CrashHandlerData data = new CrashHandlerData();
        data.setTime(time);
        savePhoneInfo(data, ex);

        /**
         * 将本地保存的异常信息文件回调
         * 用以上传服务器
         */
        if (mListener != null) {
            mListener.onExceptionData(data);
        }

    }

    /**
     * 写入手机基本信息   异常机型   异常原因等
     * @param data
     * @param ex
     * @throws PackageManager.NameNotFoundException
     */
    private void savePhoneInfo(CrashHandlerData data, Throwable ex) throws PackageManager.NameNotFoundException {
        PackageManager pm = mContext.getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);

        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        ex.printStackTrace(pw);

        data.setApp_versionName(pi.versionName);
        data.setApp_versionCode(pi.versionCode);
        data.setOS_Version(Build.VERSION.RELEASE);
        data.set_sdk(Build.VERSION.SDK_INT);
        data.setVendor(Build.MANUFACTURER);
        data.setModel(Build.MODEL);
        data.setCPU_ABI(Build.CPU_ABI);
        data.setThrowable(sw.toString());
    }
}
